﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;


public class InputManager
{
    /**
     * The following list of variables are static constants for the specific controls used in Colossal Crisis.
     * Their corresponding index is used to tell the InputManager class which index in the controls Array holds
     * the Control Object that monitors the status of its corresponding input.
     */
    public static char UP_BUTTON = 'q';
    private static int UP_INDEX = -1;
    
    public static char DOWN_BUTTON = 'w';
    private static int DOWN_INDEX = -1;
    
    public static char LEFT_BUTTON = 'e';
    private static int LEFT_INDEX = -1;
    
    public static char RIGHT_BUTTON = 'r';
    private static int RIGHT_INDEX = -1;
    
    public static char DYNAMITE_BUTTON = 't';
    private static int DYNAMITE_INDEX = -1;
    
    public static char JUMP_BUTTON = 'y';
    private static int JUMP_INDEX = -1;
    
    public static char USE_BUTTON = 'u';
    private static int USE_INDEX = -1;
    
    public static char GRAB_BUTTON = 'i';
    private static int GRAB_INDEX = -1;
    
    public static char JETPACK_BUTTON = 'o';
    private static int JETPACK_INDEX = -1;
    
    public static char PAUSE_BUTTON = 'p';
    private static int PAUSE_INDEX = -1;
    
    public static char BACK_BUTTON = 'a';
    private static int BACK_INDEX = -1;
   
    public static bool RIGHT_ANALOG_UP = false;
    public static bool RIGHT_ANALOG_DOWN = false;
    public static bool RIGHT_ANALOG_LEFT = false;
    public static bool RIGHT_ANALOG_RIGHT = false;
    public static bool LEFT_ANALOG_UP = false;
    public static bool LEFT_ANALOG_DOWN = false;
    public static bool LEFT_ANALOG_LEFT = false;
    public static bool LEFT_ANALOG_RIGHT = false;
    
    private float analogThreshold = 0.25f;

    /**
     * This ArrayList holds all of the Control objects that correspond to specific inputs to the game (i.e. up, down, jump, use, etc.)
     */
    public ArrayList controls;
    
    
    private static InputManager im = null;
    
    /** 
     * InputManager is a Singleton class, and thus has a private Contruct 
     * 
     */
    private InputManager()
    {
        propigateControls();
    }

    /** 
     * returns a single InputManager object
     */

    public static InputManager getSingleton()
    {
        if (im == null)
        {
            im = new InputManager();
        }
        return im;
    }

    /** 
     * Adds a control object to the controls ArrayList
     */

    public int addControl(char controlType, Microsoft.Xna.Framework.Input.Buttons button, Microsoft.Xna.Framework.Input.Keys key)
    {
        return controls.Add(new Control(button, key, controlType));

    }

    /** 
     * This method polls all of the control objects and checks if the associated XNA button or key states are pressed.
     * It also checks to see what the current values of both analog sticks are, and flips their associated boolean flags if appropriate.
     */

    public void checkControls()
    {
        /**
         * Poll the buttons, set the isJustPressed only AFTER a control button or key has been pressed. Decrement the isJustPressed counter
         * until it reaches 0 and set isJustPressed to false.
         */
        
        for (int i = 0; i < controls.Count; i++)
        {
            Control control = ((Control)controls[i]);
            if (GamePad.GetState(PlayerIndex.One).IsButtonDown(control.button) || Keyboard.GetState().IsKeyDown(control.key))
            {
                control.isPressed = true;
                if (control.justPressedValue == 0)
                {
                    control.isJustPressed = true;
                    control.justPressedValue = 1;
                }
                else if(control.justPressedValue == 1)
                {
                    control.isJustPressed = false;
                }
                
            } else 
            {
                control.justPressedValue = 0;
                control.isPressed = false;
                control.isJustPressed = false;
            }
        }

        /** 
         * Check the left analog stick
         */

        if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.X > analogThreshold)
        {
            LEFT_ANALOG_RIGHT = true;
        }
        else
        {
            LEFT_ANALOG_RIGHT = false;
        }

        if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.X < -analogThreshold)
        {
            LEFT_ANALOG_LEFT = true;
        }
        else
        {
            LEFT_ANALOG_LEFT = false;
        }

        if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y > analogThreshold)
        {
            LEFT_ANALOG_UP = true;
        }
        else
        {
            LEFT_ANALOG_UP = false;
        }

        if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y < -analogThreshold)
        {
            LEFT_ANALOG_DOWN = true;
        }
        else
        {
            LEFT_ANALOG_DOWN = false;
        }

        /**
         * Check the right analog stick
         */

        if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.X > analogThreshold)
        {
            RIGHT_ANALOG_RIGHT = true;
        }
        else
        {
            RIGHT_ANALOG_RIGHT = false;
        }

        if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.X < -analogThreshold)
        {
            RIGHT_ANALOG_LEFT = true;
        }
        else
        {
            RIGHT_ANALOG_LEFT = false;
        }

        if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.Y > analogThreshold)
        {
            RIGHT_ANALOG_UP = true;
        }
        else
        {
            RIGHT_ANALOG_UP = false;
        }

        if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.Y < -analogThreshold)
        {
            RIGHT_ANALOG_DOWN = true;
        }
        else
        {
            RIGHT_ANALOG_DOWN = false;
        }

    }

    /** 
     * adds all game controls to the controls ArrayList, and sets their corresponding index value to their index in
     * the controls ArrayList.
     */

    public void propigateControls()
    {
        controls = new ArrayList();
        
        UP_INDEX = addControl(UP_BUTTON, Microsoft.Xna.Framework.Input.Buttons.DPadUp, Microsoft.Xna.Framework.Input.Keys.Up);
        DOWN_INDEX = addControl(DOWN_BUTTON, Microsoft.Xna.Framework.Input.Buttons.DPadDown, Microsoft.Xna.Framework.Input.Keys.Down);
        LEFT_INDEX = addControl(LEFT_BUTTON, Microsoft.Xna.Framework.Input.Buttons.DPadLeft, Microsoft.Xna.Framework.Input.Keys.Left);
        RIGHT_INDEX = addControl(RIGHT_BUTTON, Microsoft.Xna.Framework.Input.Buttons.DPadRight, Microsoft.Xna.Framework.Input.Keys.Right);
        DYNAMITE_INDEX = addControl(DYNAMITE_BUTTON, Microsoft.Xna.Framework.Input.Buttons.B, Microsoft.Xna.Framework.Input.Keys.A);
        JUMP_INDEX = addControl(JUMP_BUTTON, Microsoft.Xna.Framework.Input.Buttons.A, Microsoft.Xna.Framework.Input.Keys.D);
        USE_INDEX = addControl(USE_BUTTON, Microsoft.Xna.Framework.Input.Buttons.X, Microsoft.Xna.Framework.Input.Keys.S);
        GRAB_INDEX = addControl(GRAB_BUTTON, Microsoft.Xna.Framework.Input.Buttons.Y, Microsoft.Xna.Framework.Input.Keys.E);
        JETPACK_INDEX = addControl(JETPACK_BUTTON, Microsoft.Xna.Framework.Input.Buttons.RightShoulder, Microsoft.Xna.Framework.Input.Keys.W);
        PAUSE_INDEX = addControl(PAUSE_BUTTON, Microsoft.Xna.Framework.Input.Buttons.Start, Microsoft.Xna.Framework.Input.Keys.Enter);
        BACK_INDEX = addControl(BACK_BUTTON, Microsoft.Xna.Framework.Input.Buttons.Back, Microsoft.Xna.Framework.Input.Keys.Escape);
    }

    /**
     * This method is called by the Game's update method. It polls all the keys, buttons, and analog inputs and sets 
     * their states accordingly.
     */
    public void update()
    {
        checkControls();
    }

    /**
     * Changes a game control's keyboard key and the gamepad button
     */
    public void modifyControl(char controlType, Microsoft.Xna.Framework.Input.Buttons button, Microsoft.Xna.Framework.Input.Keys key)
    {
        Control c = (Control) controls[getIndex(controlType)];
        c.changeKey(key);
        c.changeButton(button);
    }


    /** 
     * Changes a game control's gamepad button
     */
    public void modifyControl(char controlType, Microsoft.Xna.Framework.Input.Buttons button)
    {
        Control c = (Control)controls[getIndex(controlType)];
        c.changeButton(button);
    }

    /** 
     * Changes a game control's keyboard key
     */

    public void modifyControl(char controlType, Microsoft.Xna.Framework.Input.Keys key)
    {
        Control c = (Control) controls[getIndex(controlType)];
        c.changeKey(key);
    }

    /**
     * returns the index of a specific control type from the controls ArrayList
     */
    private int getIndex(char controlType){
        if (controlType == UP_BUTTON)
        {
            return UP_INDEX;
        }
        else if (controlType == DOWN_BUTTON)
        {
            return DOWN_INDEX;
        }
        else if (controlType == LEFT_BUTTON)
        {
            return LEFT_INDEX;
        }
        else if (controlType == RIGHT_BUTTON)
        {
            return RIGHT_INDEX;
        }
        else if (controlType == JUMP_BUTTON)
        {
            return JUMP_INDEX;
        }
        else if (controlType == DYNAMITE_BUTTON)
        {
            return DYNAMITE_INDEX;
        }
        else if (controlType == USE_BUTTON)
        {
            return USE_INDEX;
        }
        else if (controlType == GRAB_BUTTON)
        {
            return GRAB_INDEX;
        }
        else if (controlType == JETPACK_BUTTON)
        {
            return JETPACK_INDEX;
        }
        else if (controlType == BACK_BUTTON)
        {
            return BACK_INDEX;
        }
        else if (controlType == PAUSE_BUTTON)
        {
            return PAUSE_INDEX;
        }
        else return 'x';
    }

    /**
     * returns the state of the requested control
     */

    public Boolean getControlState(char inputType){
        return ((Control) controls[getIndex(inputType)]).isPressed;
    }

    /** 
     * returns the toggled state of the requested control
     */
    public Boolean getToggledControlState(char inputType)
    {
        return ((Control)controls[getIndex(inputType)]).isToggled;
    }

    public Boolean getJustPressedControlState(char inputType)
    {
        return ((Control)controls[getIndex(inputType)]).isJustPressed;
    }
}
